/**
 * Copyright 2018 asiainfo Inc.
 **/
package com.myz.rabbitmq.common.listener;

import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * 责接收处理订单服务发送的消息
 *
 * @author maoyz on 2018/8/28
 * @version: v1.0
 */
@Component
@Slf4j
@PropertySource(value = "classpath:config/rabbit.properties", encoding = "utf-8")
@RabbitListener(queuesToDeclare = @Queue("aa"))
public class OrderConsumer {

    @Value("${rabbit.name.queue.01}")
    private String queueName1;

    private final String QUEUE_NAME1 = "first-queue";
    private final String QUEUE_NAME2 = "second-queue";


    /**
     * 订阅消息 @RabbitListener，queues参数指定从哪个队列订阅消息
     *
     * @param message
     * @param channel
     */
    // @RabbitListener(queues = {QUEUE_NAME1})
    public void handleMessage(Message message, Channel channel) throws IOException {
        log.info("消费者 start consume message");

        try {
            // 处理消息
            log.info("OrderConsumer {} handleMessage :"
                    + "body{}:" + message.getBody()
                    + ", exchange{}:" + message.getMessageProperties().getReceivedExchange()
                    + ", deliveryTag{}:" + message.getMessageProperties().getDeliveryTag()
                    + ", routingKey" + message.getMessageProperties().getReceivedRoutingKey()
                    + ", queue{}:" + message.getMessageProperties().getConsumerQueue());

            // 处理业务
            int order = 0;

            if (order == 0) {
                log.info("执行success");
            } else {
                log.error("执行fail");
            }

            /*
             * 第一个参数 deliveryTag：就是接受的消息的deliveryTag,可以通过msg.getMessageProperties().getDeliveryTag()获得
             * 第二个参数 multiple：如果为true，确认之前接受到的消息；如果为false，只确认当前消息。
             * 如果为true就表示连续取得多条消息才发会确认，和计算机网络的中tcp协议接受分组的累积确认十分相似，能够提高效率。
             *
             * 同样的，如果要nack或者拒绝消息（reject）的时候，
             * 也是调用channel里面的basicXXX方法就可以了（要指定tagId）。
             *
             * 注意：如果抛异常或nack（并且requeue为true），消息会重新入队列，
             * 并且会造成消费者不断从队列中读取同一条消息的假象。
             */
            // 确认消息
            // 如果 channel.basicAck   channel.basicNack  channel.basicReject 这三个方法都不执行，消息也会被确认
            // 所以，正常情况下一般不需要执行 channel.basicAck

            // 消息的标识，false只确认当前一个消息收到，true确认consumer获得的所有消息
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
        } catch (Exception e) {
            log.error("OrderConsumer  handleMessage {} , error:", message, e);

            if (message.getMessageProperties().getRedelivered()) {
                log.error("消息已重复处理失败,拒绝再次接收...");

                // 拒绝消息
                channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
            } else {
                log.error("消息即将再次返回队列处理...");

                // ack返回false，并重新回到队列
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
            }
        }
    }

    // @RabbitListener(queues = {QUEUE_NAME2})
    public void processMessage() {

    }
}


